package com.gitee.wsl.mathematics.geometry.d2.triangle.delaunay

import com.gitee.wsl.mathematics.geometry.d2.line.EdgeDistancePack
import com.gitee.wsl.mathematics.geometry.d2.line.Line
import com.gitee.wsl.mathematics.geometry.d2.triangle.Triangle
import com.gitee.wsl.mathematics.geometry.d2.triangle.ext.findNearestEdge
import com.gitee.wsl.mathematics.geometry.d2.triangle.ext.isNeighbour
import com.gitee.wsl.mathematics.vector.vec2.Vec2f

/**
 * Triangle soup class implementation.
 *
 * @author Johannes Diemke
 */
internal class TriangleSoup {
    private val triangleSoup: HashSet<Triangle> = HashSet()

    /**
     * Adds a triangle to this triangle soup.
     *
     * @param triangle
     * The triangle to be added to this triangle soup
     */
    fun add(triangle: Triangle) {
        triangleSoup.add(triangle)
    }

    /**
     * Removes a triangle from this triangle soup.
     *
     * @param triangle
     * The triangle to be removed from this triangle soup
     */
    fun remove(triangle: Triangle) {
        triangleSoup.remove(triangle)
    }

    val triangles: List<Triangle>
        /**
         * Returns the triangles from this triangle soup.
         *
         * @return The triangles from this triangle soup
         */
        get() = ArrayList(this.triangleSoup)

    /**
     * Returns the triangle from this triangle soup that contains the specified
     * point or null if no triangle from the triangle soup contains the point.
     *
     * @param point
     * The point
     * @return Returns the triangle from this triangle soup that contains the
     * specified point or null
     */
    fun findContainingTriangle(point: Vec2f): Triangle? {
        for (triangle in triangleSoup) {
            if (triangle.containsPoint(point)) {
                return triangle
            }
        }
        return null
    }

    /**
     * Returns the neighbor triangle of the specified triangle sharing the same
     * edge as specified. If no neighbor sharing the same edge exists null is
     * returned.
     *
     * @param triangle
     * The triangle
     * @param edge
     * The edge
     * @return The triangles neighbor triangle sharing the same edge or null if
     * no triangle exists
     */
    fun findNeighbour(triangle: Triangle, edge: Line): Triangle? {
        for (triangleFromSoup in triangleSoup) {
            if (triangleFromSoup.isNeighbour(edge) && triangleFromSoup !== triangle) {
                return triangleFromSoup
            }
        }
        return null
    }

    /**
     * Returns one of the possible triangles sharing the specified edge. Based
     * on the ordering of the triangles in this triangle soup the returned
     * triangle may differ. To find the other triangle that shares this edge use
     * the [] method.
     *
     * @param edge
     * The edge
     * @return Returns one triangle that shares the specified edge
     */
    fun findOneTriangleSharing(edge: Line): Triangle? {
        for (triangle in triangleSoup) {
            if (triangle.isNeighbour(edge)) {
                return triangle
            }
        }
        return null
    }

    /**
     * Returns the edge from the triangle soup nearest to the specified point.
     *
     * @param point
     * The point
     * @return The edge from the triangle soup nearest to the specified point
     */
    fun findNearestEdge(point:Vec2f): Line {
        val edgeList: MutableList<EdgeDistancePack<Float,Line>> = ArrayList()

        for (triangle in triangleSoup) {
            edgeList.add(triangle.findNearestEdge(point))
        }

       /* val edgeDistancePacks: Array<EdgeDistancePack<*, *>> = arrayOfNulls(edgeList.size)
        edgeList.toArray<EdgeDistancePack<*, *>>(edgeDistancePacks)

        java.util.Arrays.sort(edgeDistancePacks)
        return edgeDistancePacks[0].edge*/
        return edgeList.sortedBy { a -> a.distance }[0].edge
    }

    /**
     * Removes all triangles from this triangle soup that contain the specified
     * vertex.
     *
     * @param vertex
     * The vertex
     */
    fun removeTrianglesUsing(vertex:Vec2f) {
        val trianglesToBeRemoved: MutableList<Triangle> = ArrayList<Triangle>()

        for (triangle in triangleSoup) {
            if (triangle.hasVertex(vertex)) {
                trianglesToBeRemoved.add(triangle)
            }
        }

        triangleSoup.removeAll(trianglesToBeRemoved)
    }
}